package com.example.demo.handler.imp;

import com.example.demo.Application;
import com.example.demo.handler.SendHandler;
import com.example.demo.service.CacheService;
import com.example.demo.service.ChannelService;
import com.example.demo.support.cache.ChannelCache;
import com.example.demo.support.constant.ChannelConstant;
import com.example.demo.support.constant.ParamKeyConstant;
import com.example.demo.util.RedisCacheManager;
import com.example.demo.work.GatewayOperator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;

/**
 * Created by gumingmin on 16-6-23.
 */
public abstract class BaseHandler implements SendHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(BaseHandler.class);
    @Resource
    private ChannelService channelService;
    @Resource
    CacheService cacheService;
    @Resource
    private RedisCacheManager redisCacheManager;

    //连接发送服务器的时间,3秒
    private static final int CONNECT_TIMEOUT = 3 * 1000;
    //等待发送服务器返回的时间,假设通道商最慢也能在60分钟之内返回
    private static final int READ_TIMEOUT = 60 * 60 * 1000;
    private static final String INVOKE_REMOTE_MSG_PREFIX = "invoke_remote_server_error_";

    public static boolean manualCancelSend(Map<String, Object> transitMap) {
        return ChannelConstant.SEND_LEVEL_CANCELED.equals(String.valueOf(transitMap.get(ParamKeyConstant.SEND_LEVEL)));
    }

    public void handle(final GatewayOperator unit) {
        final int gatewayId = unit.getGatewayId();
        final String threadName = Thread.currentThread().getName();
        final String channelType = cacheService.getChannelNameByGatewayId(gatewayId);

        while (true) {
//            =====================================判断是否可以发送,开始=====================================
            if (!unit.isSendHandleAllowed()) {
                LOGGER.info("通道[" + gatewayId + "]无效,不进行发送");
                break;
            }
            if (!unit.isSendTimeAllowed()) {
                LOGGER.info("通道[" + gatewayId + "]不在通道发送时间区间内,不进行发送");
                break;
            }
            if (StringUtils.isEmpty(unit.getSendConfig())) {
                LOGGER.info("通道[" + gatewayId + "]发送配置为空,不进行发送");
                break;
            }
            if (unit.getMaxTaskFetchSize() <= 0) {
                LOGGER.info("通道[" + gatewayId + "]每次获取子任务量为0,不进行发送");
                break;
            }
            long currentRunningTreadNum = unit.getCurrentRunningTreadNum();
            int maxConcurrentThreadNum = unit.getMaxConcurrentThreadNum();
            if (currentRunningTreadNum > maxConcurrentThreadNum) {
                LOGGER.info("通道[" + gatewayId + "]当前线程数[{}]已超过允许最大线程数[{}],不进行发送", currentRunningTreadNum, maxConcurrentThreadNum);
                break;
            }
//            =====================================判断是否可以发送,结束=====================================
//            =====================================获取发送任务,开始=====================================
            final String competeId = threadName + "-" + System.currentTimeMillis() + "-" + Application.SERVER_NAME_ID;
            Semaphore gatewaySemaphore = ChannelCache.GATEWAY_SYNC_LOCK_MAP.computeIfAbsent(gatewayId, (k) -> new Semaphore(1, true));
            gatewaySemaphore.acquireUninterruptibly();
            try {
                LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->开始获取任务, 使用同步器:" + gatewaySemaphore);
                try {
                    Thread.sleep(1);
                } catch (InterruptedException in) {
                    //ignore
                }
                channelService.updateTransitCurrentThreadid(competeId, gatewayId, unit.getMaxTaskFetchSize());
            } catch (Exception fetchCurrentTransitException) {
                LOGGER.error("通道{}获取发送任务异常,释放许可,线程退出, 同步器:" + gatewaySemaphore, gatewayId, fetchCurrentTransitException);
                break;
            } finally {
                LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->结束获取任务, 释放同步器:" + gatewaySemaphore);
                gatewaySemaphore.release();
            }
//            =====================================获取发送任务,结束=====================================
//            ==================实际发送==================
            final List<Map<String, Object>> currentTransitList = channelService.getTransitCurrent("ChannelMapper.get" + channelType + "TransitCurrent", gatewayId, competeId);
            if (currentTransitList == null || currentTransitList.size() == 0) {
                LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->没有获取到更多的发送的任务,退出循环");
                break;
            }
            List<Object> pkidList = currentTransitList.stream().map(m -> m.get(ParamKeyConstant.PKID)).collect(Collectors.toList());
            final List<Map<String, Object>> receiptMapList = new ArrayList<>();
            final List<Map<String, Object>> backAccountMapList = new ArrayList<>();
            final List<Map<String, Object>> sendSourceList = new ArrayList<>();
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->获取到发送任务:" + pkidList);
            handleEachSubTaskSend(unit, gatewayId, threadName, channelType, currentTransitList, receiptMapList, backAccountMapList, sendSourceList);
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->结束操作所有业务:" + pkidList);
            handleTransitCurrentAndTransitResult(currentTransitList, getHandledSubTaskIdList(currentTransitList));
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->结束操作任务属性表:" + pkidList);
            revertChargeIfFail(backAccountMapList);//恢复费用如果失败
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->操作还款任务:" + pkidList);
            handleReceipt(channelType, receiptMapList);
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->操作通道商回执:" + pkidList);
            handleSendSource(sendSourceList);
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->操作发送结果的写入:" + pkidList);
//            buildSentSubTasksMessageAndSend(currentTransitList);
            //LOGGER.info("线程[" + threadName + "]使用标记[" + competeId + "]获取通道[" + gatewayId + "]发送任务->结束业务数据发送:" + pkidList);
        }
    }

    private void handleEachSubTaskSend(GatewayOperator unit, int gatewayId, String threadName, String channelType, List<Map<String, Object>> currentTransitList, List<Map<String, Object>> receiptMapList, List<Map<String, Object>> backAccountMapList, List<Map<String, Object>> sendSourceList) {
        for (Map<String, Object> currentTransit : currentTransitList) {
            final Integer transitId = (Integer) currentTransit.get(ParamKeyConstant.PKID);
            final String subTaskId = (String) currentTransit.get(ParamKeyConstant.SUB_TASK_ID);
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->开始执行发送任务:[" + transitId + "]-[" + subTaskId + "]");
            boolean isSendAvailable =
                    getSubTaskGatewayConfig(unit, gatewayId, threadName, channelType, currentTransit, transitId, subTaskId)
                            &&
                            getSubTaskSendDetail(gatewayId, threadName, currentTransit, transitId, subTaskId);
            if (isSendAvailable) {
                currentTransit = handleSubTaskSend(gatewayId, threadName, currentTransit, transitId, subTaskId);
            }
            delRedisData(subTaskId);
            handleSubTaskReceipt(receiptMapList, currentTransit);
            handleSubTaskRevertCharge(gatewayId, channelType, backAccountMapList, currentTransit, checkSubTaskStatus(currentTransit, subTaskId));
            handleSubTaskSendSource(sendSourceList, currentTransit);
        }
    }

    private boolean getSubTaskGatewayConfig(GatewayOperator unit, int gatewayId, String threadName, String channelType, Map<String, Object> currentTransit, Integer currentPkId, String subTaskId) {
        try {
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->获取通道发送配置:[" + currentPkId + "]-[" + subTaskId + "]");
            currentTransit.put(ParamKeyConstant.CHANNEL_TYPE, channelType);
            currentTransit.put(ParamKeyConstant.SP_ID, cacheService.getGatewayDetailCache(gatewayId).get(ParamKeyConstant.SP_ID));
            currentTransit.put(ParamKeyConstant.GATEWAY_ID, gatewayId);
            currentTransit.put(ParamKeyConstant.SEND_CONFIG, unit.getSendConfig());
            //获取发送配置
            getGatewaySendConfig(currentTransit);
            return true;
        } catch (Exception buildGatewayConfigError) {
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]获取通道配置异常", buildGatewayConfigError);
            currentTransit.putIfAbsent(ParamKeyConstant.STATUS, 2);
            currentTransit.putIfAbsent(ParamKeyConstant.ERR_CODE, buildGatewayConfigError.getMessage());
            return false;
        }
    }

    private boolean getSubTaskSendDetail(int gatewayId, String threadName, Map<String, Object> currentTransit, Integer currentPkId, String subTaskId) {
        try {
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->获取发送数据:[" + currentPkId + "]-[" + subTaskId + "]");
            getSendDetail(currentTransit);
            return true;
        } catch (SendDetailErrorException sendDetailError) {
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]获取发送数据异常", sendDetailError);
            currentTransit.putIfAbsent(ParamKeyConstant.STATUS, 2);
            currentTransit.putIfAbsent(ParamKeyConstant.ERR_CODE, sendDetailError.getMessage());
            return false;
        }
    }

    private Map<String, Object> handleSubTaskSend(int gatewayId, String threadName, Map<String, Object> currentTransit, Integer currentPkId, String subTaskId) {
        LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]开始发送");
        try {
            if (testSend(currentTransit)) {
                LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]测试发送");
            } else if (cancelSend(currentTransit)) {
                LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]取消发送");
            } else {
                currentTransit = sendByServiceProvider(currentTransit);
                LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]发送结束");
            }
        } catch (Exception handleSendException) {
            LOGGER.info("线程[" + threadName + "]获取通道[" + gatewayId + "]发送任务->执行发送任务:[" + currentPkId + "]-[" + subTaskId + "]发送异常", handleSendException);
            currentTransit.putIfAbsent(ParamKeyConstant.STATUS, 2);
            currentTransit.putIfAbsent(ParamKeyConstant.ERR_CODE, subTaskId + "-" + handleSendException.getMessage());
        }
        return currentTransit;
    }

    private void handleSubTaskSendSource(List<Map<String, Object>> sendSourceList, Map<String, Object> currentTransit) {
        List<Map<String, Object>> sendSource = (List<Map<String, Object>>) currentTransit.get(ParamKeyConstant.SEND_SOURCE);
        if (sendSource != null && sendSource.size() > 0) {
            sendSourceList.addAll(sendSource);
        }
    }

    private void handleSubTaskRevertCharge(int gatewayId, String channelType, List<Map<String, Object>> backAccountMapList, Map<String, Object> currentTransit, Integer status) {
        if (status.equals(2) && isBalance(gatewayId)) {
            if (channelType.equals(ChannelConstant.CHANNEL_TYPE_SMS)) {
                currentTransit.put(ParamKeyConstant.BACK_NUMBER, currentTransit.get(ParamKeyConstant.CONTENT_SIZE));
            }
            if (channelType.equals(ChannelConstant.CHANNEL_TYPE_EDM) || channelType.equals(ChannelConstant.CHANNEL_TYPE_VSMS)) {
                currentTransit.put(ParamKeyConstant.BACK_NUMBER, currentTransit.get(ParamKeyConstant.DATA_SIZE));
            }
            backAccountMapList.add(currentTransit);
        }
    }

    private void handleSubTaskReceipt(List<Map<String, Object>> receiptMapList, Map<String, Object> currentTransit) {
        if (!StringUtils.isEmpty(currentTransit.get(ParamKeyConstant.RECEIPT))) {
            receiptMapList.add(currentTransit);
        }
    }

    private Integer checkSubTaskStatus(Map<String, Object> currentTransit, String subTaskId) {
        Integer status = (Integer) currentTransit.get(ParamKeyConstant.STATUS);
        if (status == null || (!status.equals(3) && !status.equals(2))) {
            throw new SentStatusNotFoundRuntimeException(subTaskId + "-发送结果状态不对(2失败,3成功)");
        }
        return status;
    }

    private List<Integer> getHandledSubTaskIdList(List<Map<String, Object>> currentTransitList) {
        return currentTransitList.stream().map((m) -> (Integer) m.get(ParamKeyConstant.PKID)).collect(Collectors.toList());
    }

    /**
     * 正式的由通道商发送数据
     */
    private Map<String, Object> sendByServiceProvider(Map<String, Object> transitMap) throws Exception {
        String sendConfig = (String) transitMap.get(ParamKeyConstant.SEND_CONFIG);
        if (!StringUtils.isEmpty(sendConfig)) {
            Map<String, Object> sendInfo = selectSendInfo(transitMap);
            Map<String, Object> afterSendInf = sendHandle(sendInfo, sendConfig);//正式发送
            if (afterSendInf == null) {
                throw new Exception("发送返回的结果集不能为空");
            }
            return modifyTransitMapWithResultInfo(transitMap, afterSendInf);
        } else {
            transitMap.put(ParamKeyConstant.ERR_CODE, "通道商实现类不存在");
            throw new Exception("通道商实现类不存在");
        }
    }

    private void getGatewaySendConfig(Map<String, Object> transitMap) {
        //获取发送配置
        Map<String, Object> gatewayDetailMap = cacheService.getGatewayDetailCache((Integer) transitMap.get(ParamKeyConstant.GATEWAY_ID));
        transitMap.put(ParamKeyConstant.GATEWAY_CONFIG_1, gatewayDetailMap.get("sparefiled1"));
        transitMap.put(ParamKeyConstant.GATEWAY_CONFIG_2, gatewayDetailMap.get("sparefiled2"));
        transitMap.put(ParamKeyConstant.GATEWAY_CONFIG_3, gatewayDetailMap.get("sparefiled3"));
    }

    private void handleSendSource(List<Map<String, Object>> sendSourceList) {
        if (sendSourceList != null && sendSourceList.size() > 0) {
            try {
                persistSendDetail(sendSourceList);
            } catch (Exception e1) {
                LOGGER.error("插入Source数据异常：", e1);
            }
        }
    }

    private void handleReceipt(String channelType, List<Map<String, Object>> receiptMapList) {
        if (receiptMapList != null && receiptMapList.size() > 0) {
            try {
                channelService.insertMessage("ChannelMapper.insert" + channelType + "Message", receiptMapList);
            } catch (Exception e1) {
                LOGGER.error("插入receipt数据异常：", e1);
            }
        }
    }

    private void revertChargeIfFail(List<Map<String, Object>> backAccountMapList) {
        if (backAccountMapList != null && backAccountMapList.size() > 0) {
            try {
                channelService.insertBackAccount(backAccountMapList);
            } catch (Exception e1) {
                LOGGER.error("插入backAccount数据异常：", e1);
            }
        }
    }

    private void handleTransitCurrentAndTransitResult(List<Map<String, Object>> transitMapList, List<Integer> pkidList) {
        if (transitMapList != null && transitMapList.size() > 0) {
            try {
                channelService.insertCompleteTransitAndDeleteCurrent(transitMapList, pkidList);
            } catch (Exception e1) {
                LOGGER.error("插入succTransit数据异常：", e1);
            }
        }
    }

    private boolean isBalance(Integer gatewayId) {//是否有钱的概念
        Map<String, Object> gatewayDetailMap = cacheService.getGatewayDetailCache(gatewayId);
        Integer spId = (Integer) gatewayDetailMap.get(ParamKeyConstant.SP_ID);
        Map gatewayMap = cacheService.getGatewayCache(spId);
        return !gatewayMap.get("ballance_type").equals(0);
    }

    private void delRedisData(String subTaskId) {
        try {
            redisCacheManager.del(subTaskId);
        } catch (Exception e) {
            LOGGER.error(subTaskId + "删除redis KEY异常", e);
        }
    }

//    private void buildSentSubTasksMessageAndSend(List<Map<String, Object>> transitMapList) {
//        for (Map<String, Object> transitMap : transitMapList) {
//            Map<String, Object> msgMap = new HashMap<>();
//            msgMap.put(ParamKeyConstant.TASK_ID, transitMap.get(ParamKeyConstant.TASK_ID));
//            msgMap.put(ParamKeyConstant.SUB_TASK_ID, transitMap.get(ParamKeyConstant.SUB_TASK_ID));
//            msgMap.put(ParamKeyConstant.STATUS, transitMap.get(ParamKeyConstant.STATUS));
//            if ((transitMap.get(ParamKeyConstant.CHANNEL_TYPE)).equals(ChannelConstant.CHANNEL_TYPE_SMS)) {
//                msgMap.put(ParamKeyConstant.CONTENT_SIZE, transitMap.get(ParamKeyConstant.CONTENT_SIZE));
//            } else {
//                msgMap.put(ParamKeyConstant.CONTENT_SIZE, transitMap.get(ParamKeyConstant.DATA_SIZE));
//            }
//            String msg = null;
//            try {
//                msg = new ObjectMapper().writeValueAsString(msgMap);
//            } catch (JsonProcessingException e) {
//                // 我觉得真的不可能出异常,不存在的锅
//                LOGGER.error("msg转换异常", e);
//            }
//            sendMsg((String) transitMap.get(ParamKeyConstant.SUB_TASK_ID), msg);
//        }
//    }

//    private void sendMsg(String remark, String msg) {
//        try {
//            String mq_cs_address = PropertyDelegateUtil.getOrException("MQ_CS_ADDRESS", PropsUtil::getSysOrEnv);
//            String mq_cs_vhost = PropertyDelegateUtil.getOrException("MQ_CS_VHOST", PropsUtil::getSysOrEnv);
//            String mq_cs_username = PropertyDelegateUtil.getOrException("MQ_CS_USERNAME", PropsUtil::getSysOrEnv);
//            String mq_cs_password = PropertyDelegateUtil.getOrException("MQ_CS_PASSWORD", PropsUtil::getSysOrEnv);
//            MqUtil.ConnectionMeta connectionMeta = MqUtil.ConnectionMeta.newInstance(mq_cs_address, mq_cs_vhost, mq_cs_username, mq_cs_password);
//            MqUtil.sendExchange(connectionMeta, "EXCHANGE_CS_RECEIVE", msg);
//        } catch (Exception e) {
//            LOGGER.error(remark + "发送MQ异常", e);
//        }
//        LOGGER.info("{}:发送MQ完成", remark);
//    }

    /**
     * transitMap.put(afterSendInf.get)
     *
     * @param transitMap   返回数据的容器
     * @param afterSendInf 发送返回的数据容器
     * @return 经过修改的transitMap
     */
    protected abstract Map<String, Object> modifyTransitMapWithResultInfo(Map<String, Object> transitMap, Map<String, Object> afterSendInf) throws IOException;

    /**
     * 只获取发送必须的数据,不是必须的数据不应当被放入, 减少网络带宽消耗
     *
     * @param transitMap
     * @return 一个新的map, 不应当直接返回作为参数使用的map
     */
    protected abstract Map<String, Object> selectSendInfo(Map<String, Object> transitMap);

    public abstract void getSendDetail(Map<String, Object> transitMap) throws SendDetailErrorException;

    public abstract boolean testSend(Map<String, Object> transitMap) throws Exception;

    public abstract boolean cancelSend(Map<String, Object> transitMap) throws Exception;

    /**
     * @param sendInfo   能够支持完成发送的所需的数据的最小集合的超集
     * @param sendConfig
     * @return 返回值不能为空, 而且最少应当包含能够完成剩余发送流程的所需数据,这些返回的数据会被加入到伴随发送流程自身的map里
     * @throws Exception
     */
    public abstract Map<String, Object> sendHandle(Map<String, Object> sendInfo, String sendConfig) throws Exception;

    public abstract void persistSendDetail(List<Map<String, Object>> receiptMapList) throws Exception;

    Map<String, Object> getSendInfoMapImpl(Map<String, Object> targetTransitMap, String... keys) {
        Map<String, Object> result = new HashMap<>();
        for (String key : keys) {
            result.put(key, targetTransitMap.get(key));
        }
        return result;
    }

    /**
     * 向实际发送数据的应用服务器发送请求,暂时没有有关重试的机制, 方法中会获取调用这个方法的类名以确定访问的url,所以 这个方法应当是被实际发送handler直接调用
     *
     * @return 成功返回调用结果, 失败则自定义错误信息, 错误信息至少包含status和err_code
     * @throws IOException json转换错误
     */
//    Map<String, Object> invokeSendUrl(Map<String, Object> sendInfoMap, String sendConfigStr) throws Exception {
//        SpiStruct spiStruct = SpiStruct.fromJson(sendConfigStr);
//        List<String> domainList = spiStruct.getDomainList();
//        int port = spiStruct.getPort();
//        String subTaskId = (String) sendInfoMap.get(ParamKeyConstant.SUB_TASK_ID);
//        if (domainList != null && domainList.size() > 0) {
//            int size = domainList.size();
//            for (int i = 0; i < domainList.size(); i++) {
//                String sendUrl = domainList.get(i) + ":" + port + "/business/" + getChannelTypeByClassPath() + "/send";
//                CloseableHttpClient httpClient = HttpClients.createDefault();
//                HttpPost post = new HttpPost(sendUrl);
//                post.setProtocolVersion(HttpVersion.HTTP_1_1);
//                post.setEntity(new StringEntity(ClientJacksonUtil.getStringFrom(sendInfoMap), Charset.forName("UTF-8")));
//                post.setHeader("Accept", "application/json");
//                post.setHeader("User-Agent", "channel-submit");
//                post.setHeader("Content-Type", "application/json;charset=UTF-8");
//                post.setHeader("Cache-Control", "no-cache");
//                post.setConfig(RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(READ_TIMEOUT).build());
//                CloseableHttpResponse response = null;
//                try {
////                    LOGGER.info(subTaskId + "开始请求[" + sendUrl + "],请求信息" + sendInfoMap);
//                    response = httpClient.execute(post);
//                    int statusCode = response.getStatusLine().getStatusCode();
//                    if (statusCode == 200) {
//                        HttpEntity entity = response.getEntity();
//                        String responseBody = EntityUtils.toString(entity, "UTF-8");
////                        LOGGER.info(subTaskId + "请求[" + sendUrl + "]成功,响应体" + responseBody);
//                        return ClientJacksonUtil.getMapFrom(responseBody);
//                    } else {
//                        LOGGER.info(subTaskId + "请求[" + sendUrl + "]失败,响应码:" + statusCode + ";请求数据:" + sendInfoMap);
//                        return new HashMap<String, Object>() {{
//                            put(ParamKeyConstant.STATUS, 2);
//                            put(ParamKeyConstant.ERR_CODE, INVOKE_REMOTE_MSG_PREFIX + "not_200.调用通道商发送服务异常");
//                        }};
//                    }
//                } catch (IOException e) {
//                    LOGGER.error(subTaskId + "[" + sendUrl + "]发送流程异常," + e.getMessage(), e);
//                    if ((i + 1) == size) {//只有最后一次重试仍失败时才算真正失败
//                        return new HashMap<String, Object>() {{
//                            put(ParamKeyConstant.STATUS, 2);
//                            put(ParamKeyConstant.ERR_CODE, INVOKE_REMOTE_MSG_PREFIX + "conn_err.发送流程异常," + e.getMessage());
//                            if (taobaoChannel(sendInfoMap)) {
//                                addAdditionalData(this, sendInfoMap, e.getMessage());
//                            }
//                        }};
//                    } else {
//                        LOGGER.error(subTaskId + "[" + sendUrl + "]发送服务器未能连接成功,继续尝试连接其他服务器");
//                    }
//                } finally {
//                    if (response != null) {
//                        response.close();
//                    }
//                    httpClient.close();
//                }
//            }
//            LOGGER.info(subTaskId + "没有正确的从通道商服务返回,map:" + sendInfoMap + ";config:" + sendConfigStr);
//            return new HashMap<String, Object>() {{
//                put(ParamKeyConstant.STATUS, 2);
//                put(ParamKeyConstant.ERR_CODE, INVOKE_REMOTE_MSG_PREFIX + "unknown_err.走到这个算我的锅");
//            }};
//        } else {
//            return new HashMap<String, Object>() {{
//                put(ParamKeyConstant.STATUS, 2);
//                put(ParamKeyConstant.ERR_CODE, INVOKE_REMOTE_MSG_PREFIX + "config_err.服务配置异常");
//            }};
//        }
//    }

    private void addAdditionalData(Map<String, Object> returnMap, Map<String, Object> sendInfoMap, String message) {
        String failBuyerNicks = sendInfoMap.get(ParamKeyConstant.NICKS).toString();
        //昵称文件最后一位必须是逗号才能替换成错误信息
        failBuyerNicks = failBuyerNicks.replaceAll(",", (char) 1 + message.replace(",", "+") + ",") + (char) 1 + message.replace(",", "+");
        returnMap.put(ParamKeyConstant.SUCC_LENGTH, 0);
        returnMap.put(ParamKeyConstant.SUCC_DATA, "");
        returnMap.put(ParamKeyConstant.ERR_LENGTH, sendInfoMap.get(ParamKeyConstant.DATA_SIZE));
        returnMap.put(ParamKeyConstant.ERR_DATA, failBuyerNicks);
    }

    /**
     * 是否为淘宝渠道,如果是的话,返回的异常数据需要加上成功和失败数据
     */
    private boolean taobaoChannel(Map<String, Object> sendInfoMap) {
        Object channelType = sendInfoMap.get(ParamKeyConstant.CHANNEL_TYPE);
        return ChannelConstant.CHANNEL_TYPE_BENEFIT.equals(channelType) || ChannelConstant.CHANNEL_TYPE_COUPON.equals(channelType) || ChannelConstant.CHANNEL_TYPE_UMP.equals(channelType);
    }

    private static final String HANDLER = "Handler";

    private String getChannelTypeByClassPath() throws Exception {
        String basePackage = BaseHandler.class.getPackage().getName();
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            String className = stackTraceElement.getClassName();
            if (className.endsWith(HANDLER) && className.startsWith(basePackage) && !className.equals(BaseHandler.class.getName())) {
                return className.replace(basePackage + ".", "").replace(HANDLER, "").toLowerCase();
            }
        }
        throw new Exception("没找到对应的渠道类型...");
    }

    /**
     * 没有收件人异常
     */
    public static class SendDetailErrorException extends Exception {

        public SendDetailErrorException(String message) {
            super(message);
        }
    }

    /**
     * 单个任务处理结束,但是没有发送状态的异常
     * 发送任务无论如何都是需要返回状态的, 没有状态视为代码bug,抛出异常是不受检异常
     */
    private class SentStatusNotFoundRuntimeException extends RuntimeException {

        SentStatusNotFoundRuntimeException(String message) {
            super(message);
        }
    }
}
